package btb.engine;

import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
//import org.lwjgl.opengl.GL11;

import de.matthiasmann.twl.renderer.lwjgl.LWJGLRenderer;

import btb.net.CMetaClientTask;
import btb.net.CNetwork.NChatMessage;
import btb.net.CNetwork.NChatOpResults;
import btb.net.CNetwork.NUpdateChannelList;
import btb.net.CNetworkEvent;
import btb.ui.AGuiObject;
import btb.ui.CGuiHub;
import btb.ui.CGuiLobby;
import btb.ui.CGuiLogin;
import btb.util.CGuiUtils;
import btb.util.CLogger;

public class CDisplayTask extends ATask
{	
	public final boolean ALLOW_FORCED_GUI_SWITCH 	= true;
	
	public static final int NO_GUI_REQUEST			= 0;
	public static final int GUI_CONNECTION_REQUEST	= 1;
	public static final int GUI_LOGIN_REQUEST		= 2;
	
	public class NGuiState
	{
		public static final int LOGIN_PAGE 			= 1;
		public static final int HUB_PAGE 			= 2;
		public static final int LOBBY_PAGE_GUEST	= 3;
		public static final int LOBBY_PAGE_HOST		= 4;
		
		public int state;
		public String winTitle;
		public int winWidth;
		public int winHeight;
		
		public NGuiState()
		{
			state = 1;
			winTitle = "Beat the Bard Prototype";
			winWidth = 400;
			winHeight = 300;
			
		}
		public NGuiState(int _guiState, String _title, int _width, int _height)
		{
			state = _guiState;
			winTitle = _title;
			winWidth = _width;
			winHeight = _height;
		}
	}
	
	public LWJGLRenderer renderer;
	
	protected CGuiLogin logingui;
	protected CGuiHub hubgui;
	protected CGuiLobby lobbyGuiGuest;
	protected CGuiLobby lobbyGuiHost;
	
	public NGuiState currentGuiState;
	public NGuiState loginState;
	public NGuiState hubState;
	public NGuiState lobbyGuestState;
	public NGuiState lobbyHostState;

	protected int currentGuiRequest;
	public String username;
	public String channelName;
	
	public CDisplayTask(int _taskId)
	{
		super(_taskId);
	}
	
	public CDisplayTask(ATask _parentTask, int _taskId)
	{
		super(_parentTask, _taskId);
	}
	
	public CDisplayTask(int _taskId, CTaskMessenger _mailbox)
	{
		super(_taskId, _mailbox);
	}
	
	public CDisplayTask(ATask _parentTask, int _taskId, CTaskMessenger _mailbox)
	{
		super(_parentTask, _taskId, _mailbox);
	}

	@Override
	public void initialize()
	{
		currentGuiRequest = NO_GUI_REQUEST;
		
		loginState = new NGuiState(NGuiState.LOGIN_PAGE, "Beat the Bard - Login", 1068, 800);
		hubState = new NGuiState(NGuiState.HUB_PAGE, "Beat the Bard - Hub", 1068, 800);
		lobbyGuestState = new NGuiState(NGuiState.LOBBY_PAGE_HOST, "Beat the Bard - Session Lobby", 1068, 800);
		lobbyHostState = new NGuiState(NGuiState.LOBBY_PAGE_HOST, "Beat the Bard - Session Lobby", 1068, 800);
		
		switchGuiState(NGuiState.LOGIN_PAGE);
		try
		{
			Display.create();
			Display.setVSyncEnabled(true);
			
			renderer = new LWJGLRenderer();
		}
		catch(Exception ex)
		{
			CGuiUtils.errMsg( ex );
			CLogger.cond_error("display", "Display( create(), setVSyncEnabled() ) called. LWJGLRenderer object instantiated. General exception thrown.");
		}
		
		// [Note]: initializeGUI() calls for gui objects used to be here, following on the heels of the instantiations.
		logingui = new CGuiLogin(this);
		hubgui = new CGuiHub(this);
		lobbyGuiGuest = new CGuiLobby(this, false);
		lobbyGuiHost = new CGuiLobby(this, true);
	}
	
	@Override
	public void update()
	{
		switch(currentGuiState.state)
		{
		case NGuiState.LOGIN_PAGE:
			logingui.initializeGUI(AGuiObject.DISPLAY_OPT_NONE);
			logingui.invoke();
			break;
		case NGuiState.HUB_PAGE:
			hubgui.initializeGUI(AGuiObject.DISPLAY_OPT_NONE);
			hubgui.invoke();
			break;
		case NGuiState.LOBBY_PAGE_GUEST:
			lobbyGuiGuest.initializeGUI(CGuiLobby.DISPLAY_OPT_GUEST);
			lobbyGuiGuest.invoke();
		case NGuiState.LOBBY_PAGE_HOST:
			lobbyGuiHost.initializeGUI(CGuiLobby.DISPLAY_OPT_GUEST);
			lobbyGuiHost.invoke();
		default:
			break;
		}
	}
	
	@Override
	public void handleEvent(CEvent _event)
	{
		if(CNetworkEvent.class.isAssignableFrom(_event.getClass()))
		{
			switch(_event.getEventType())
			{
			case CNetworkEvent.CNE_CHAT_MESSAGE:
				NChatMessage msg = (NChatMessage) _event.getEventPayload();
				sendToChatFrame(msg, null, null);
				break;
			case CNetworkEvent.CNE_CHAT_CHANNEL_OP:
				NChatOpResults ncor = (NChatOpResults) _event.getEventPayload();
				String message = "";
				
				if(ncor.operation == NChatOpResults.SEND_MSG_ATTEMPT)
				{
					message = "Your message could not be sent.";
				}
				else if(ncor.operation == NChatOpResults.SUBSCRIBE_ATTEMPT)
				{
					if(ncor.success)
						message = "You have joined channel '" + ncor.channelName + "'.";
					else
						message = "Unable to join channel '" + ncor.channelName + "'.";
				}
				else if(ncor.operation == NChatOpResults.UNSUBSCRIBE_ATTEMPT)
				{
					if(ncor.success)
						message = "You have left channel '" + ncor.channelName + "'.";
					else
						message = "Unable to leave channel '" + ncor.channelName + "'.";
				}
				
				sendToChatFrame(null, message, null);
				break;
			case CNetworkEvent.CNE_CHAT_UPDATE:
				sendToChatFrame(null, null, (NUpdateChannelList)_event.getEventPayload());
				break;
			default:
				break;
			}
		}
	}
	
	@Override
	public void handleDeath()
	{
		Display.destroy();
	}
	
	public void sendToChatFrame(NChatMessage _msg, String _message, NUpdateChannelList _clist)
	{
		if(_msg != null)
		{
			if(currentGuiState.state == NGuiState.HUB_PAGE)
				hubgui.frmHubChat.receiveChatMessage(_msg);
			if(currentGuiState.state == NGuiState.LOBBY_PAGE_GUEST)
				lobbyGuiGuest.frmLobbyChat.receiveChatMessage(_msg);
			if(currentGuiState.state == NGuiState.LOBBY_PAGE_HOST)
				lobbyGuiHost.frmLobbyChat.receiveChatMessage(_msg);
		}
		else if(_message != null)
		{
			if(currentGuiState.state == NGuiState.HUB_PAGE)
				hubgui.frmHubChat.receiveChatServerMessage(_message);
			if(currentGuiState.state == NGuiState.LOBBY_PAGE_GUEST)
				lobbyGuiGuest.frmLobbyChat.receiveChatServerMessage(_message);
			if(currentGuiState.state == NGuiState.LOBBY_PAGE_HOST)
				lobbyGuiHost.frmLobbyChat.receiveChatServerMessage(_message);
		}
		else if(_clist != null)
		{
			if(currentGuiState.state == NGuiState.HUB_PAGE)
				hubgui.populateChannelList(_clist);
		}
	}
	
	public void switchGuiState(int _newGuiState)
	{
		if(currentGuiState != null)
		{
			if(currentGuiState.state == NGuiState.LOGIN_PAGE)
				logingui.dismiss();
			else if(currentGuiState.state == NGuiState.HUB_PAGE)
				hubgui.dismiss();
			else if(currentGuiState.state == NGuiState.LOBBY_PAGE_GUEST)
				lobbyGuiGuest.dismiss();
			else if(currentGuiState.state == NGuiState.LOBBY_PAGE_HOST)
				lobbyGuiHost.dismiss();
		}
		
		switch(_newGuiState)
		{
		case NGuiState.LOGIN_PAGE:
			currentGuiState = loginState;
			break;
		case NGuiState.HUB_PAGE:
			currentGuiState = hubState;
			break;
		case NGuiState.LOBBY_PAGE_GUEST:
			currentGuiState = lobbyGuestState;
			break;
		case NGuiState.LOBBY_PAGE_HOST:
			currentGuiState = lobbyHostState;
			break;
		default: return;
		}
		
		try
		{
			Display.setDisplayMode(new DisplayMode(currentGuiState.winWidth, currentGuiState.winHeight));
		}
		catch(Exception ex)
		{
			CGuiUtils.errMsg( ex );
			CLogger.cond_error("display", "switchGuiState failed - Display( setDisplayMode() ) called; general Exception thrown.");
		}
		Display.setTitle(currentGuiState.winTitle);
	}
	
	// [Refactoring]: We probably want to move this shit to handleMail()/handleEvent() in some way.
	public void handleConnectionResults(boolean _connectionSuccess)
	{
		if(_connectionSuccess)
		{	
			if(currentGuiState.state == NGuiState.LOGIN_PAGE)
			{
				logingui.guiAttemptLogin(this.getMailbox());
				currentGuiRequest = GUI_LOGIN_REQUEST;
			}
		}
		else
		{
			if(currentGuiState.state == NGuiState.LOGIN_PAGE)
			{
				logingui.informConnectionFailure();
			}			
		}
	}
	
	public void handleLoginResults(int _loginStatus)
	{
		if(_loginStatus == CMetaClientTask.LOGIN_PASS)
		{
			if(currentGuiState.state == NGuiState.LOGIN_PAGE)
			{
				if(currentGuiRequest == GUI_LOGIN_REQUEST)
					currentGuiRequest = NO_GUI_REQUEST;
				
				switchGuiState(NGuiState.HUB_PAGE);
			}			
		}
		else
		{
			if(currentGuiState.state == NGuiState.LOGIN_PAGE)
			{
				logingui.informLoginFailure(_loginStatus);
			}			
		}
	}
	
	public synchronized int getGuiRequest(){return currentGuiRequest;}
	public synchronized void setGuiRequest(int _guiRequest){currentGuiRequest = _guiRequest;}
}
